Syntax10.Scn.Fnt FoldElems Syntax10.Scn.Fnt Syntax10b.Scn.Fnt FoldElems Syntax10.Scn.Fnt MODULE Demo; IMPORT Timer; PROCEDURE P; BEGIN Timer.Start(1); ... Timer.Stop END P; PROCEDURE Q; BEGIN Timer.Start(2); ... Timer.Stop END Q; BEGIN Timer.Init; Timer.Print; END Demo. Syntax10i.Scn.Fnt (* This module was designed for measuring the execution times of procedures but it can also be used to measure the execution time of any code. The module maintains a list of timers that can be initialized with Timer.Init and print with Timer.Print. Timer n can be started with Timer.Start(n) and stopped with Timer.Stop. The output shows the execution times of all timers (excluding nested timers) as well as the number of calls (start/stop pairs) for every timer and the relative time per call. Sample module Syntax10i.Scn.Fnt StampElems Alloc 4 May 95 Syntax10b.Scn.Fnt Documentation MODULE Timer; (*HM IMPORT Oberon, Out; CONST maxCtr = 70; maxStackSize = 256; lastTime: LONGINT; (*for TimeDiff*) overhead: LONGINT; (*overhead for measurements*) stack: ARRAY maxStackSize OF INTEGER; (*timer stack*) sp: INTEGER; (*stack pointer*) maxLevel: INTEGER; (*max. timer nesting level*) cur: INTEGER; (*current counter*) counter: ARRAY maxCtr OF RECORD time, count: LONGINT END; PROCEDURE TimeDiff* (): LONGINT; VAR t: LONGINT; diff: LONGINT; BEGIN t := Oberon.Time(); diff := t - lastTime; lastTime := t; RETURN diff END TimeDiff; PROCEDURE Init*; VAR i: INTEGER; BEGIN FOR i := 0 TO maxCtr-1 DO counter[i].count := 0; counter[i].time := 0 END; sp := -1; cur := 0; maxLevel := 0; overhead := 0; lastTime := Oberon.Time() END Init; PROCEDURE Start* (n: INTEGER); VAR t: LONGINT; BEGIN t := TimeDiff(); INC(counter[cur].time, t); INC(sp); stack[sp] := cur; cur := n; IF sp > maxLevel THEN maxLevel := sp END; INC(overhead, TimeDiff()) END Start; PROCEDURE Stop*; VAR t: LONGINT; BEGIN t := TimeDiff(); INC(counter[cur].time, t); INC(counter[cur].count); cur := stack[sp]; DEC(sp); INC(overhead, TimeDiff()) END Stop; PROCEDURE Print*; VAR totalTime, totalCount, tcall, percent: LONGINT; i, n, error: INTEGER; BEGIN IF sp >= 0 THEN Out.String("$Timer.Print called at level > 0$"); HALT(99) END; INC(counter[0].time, TimeDiff()); INC(counter[0].count); n := maxCtr - 1; WHILE counter[n].count = 0 DO DEC(n) END; totalTime := 0; totalCount := 0; FOR i := 0 TO n DO counter[i].time := counter[i].time * 10 DIV 3; (* * 1000 DIV 300 *) (*error := (counter[i].calls + counter[i].count) DIV 88 IF error > counter[i].time THEN error := counter[i].time END; DEC(counter[i].time, error); INC(overhead, error);*) INC(totalTime, counter[i].time); INC(totalCount, counter[i].count) END; Out.String(" Ctr | freq. | time [ms] | time [%] | time/call |$"); Out.String("------+---------+-----------+----------+-----------+$"); FOR i := 0 TO n DO IF totalTime = 0 THEN percent := 0 ELSE percent := counter[i].time * 1000 DIV totalTime END; IF counter[i].count = 0 THEN tcall := 0 ELSE tcall := counter[i].time * 10 DIV counter[i].count END; Out.Int(i, 4); Out.String(" |"); Out.Int(counter[i].count, 8); Out.String(" |"); Out.Int(counter[i].time, 8); Out.String(" |"); Out.Int(percent DIV 10, 5); Out.Char("."); Out.Int(percent MOD 10, 1); Out.String(" |"); Out.Int(tcall DIV 10, 6); Out.Char("."); Out.Int(tcall MOD 10, 1); Out.String(" |$") END; Out.String("------+---------+-----------+----------+-----------+$"); Out.String("total |"); Out.Int(totalCount, 8); Out.String(" |"); Out.Int(totalTime, 8); Out.String(" | 100.0 | |$$"); Out.String("Maximum nesting level = "); Out.Int(maxLevel, 0); Out.String("$Timing and counting overhead = "); overhead := overhead * 10 DIV 3; (* * 1000 DIV 300 *) Out.Int(overhead, 0); Out.String(" ms$") END Print; BEGIN Init END Timer.